#include "lua.h"
#include "lauxlib.h"
#include "cm_gpio.h"

// Lua: gpio.setup(pin, mode, pull)
// mode: "output" or "input"
// pull: "none", "up", "down"
static int l_gpio_setup(lua_State *L) {
    cm_gpio_num_e pin = (cm_gpio_num_e)luaL_checkinteger(L, 1);
    const char *mode_str = luaL_checkstring(L, 2);
    const char *pull_str = luaL_optstring(L, 3, "none");

    cm_gpio_cfg_t cfg;

    if (strcmp(mode_str, "output") == 0) {
        cfg.direction = CM_GPIO_DIRECTION_OUTPUT;
    } else {
        cfg.direction = CM_GPIO_DIRECTION_INPUT;
    }

    if (strcmp(pull_str, "up") == 0) {
        cfg.pull = CM_GPIO_PULL_UP;
    } else if (strcmp(pull_str, "down") == 0) {
        cfg.pull = CM_GPIO_PULL_DOWN;
    } else {
        cfg.pull = CM_GPIO_PULL_NONE;
    }

    int ret = cm_gpio_init(pin, &cfg);
    lua_pushboolean(L, ret == 0);
    return 1;
}

// Lua: gpio.write(pin, value)
// value: 0 for low, 1 for high
static int l_gpio_write(lua_State *L) {
    cm_gpio_num_e pin = (cm_gpio_num_e)luaL_checkinteger(L, 1);
    cm_gpio_level_e level = (cm_gpio_level_e)luaL_checkinteger(L, 2);

    int ret = cm_gpio_set_level(pin, level);
    lua_pushboolean(L, ret == 0);
    return 1;
}

// Lua: gpio.read(pin) -> value (0 or 1)
static int l_gpio_read(lua_State *L) {
    cm_gpio_num_e pin = (cm_gpio_num_e)luaL_checkinteger(L, 1);
    cm_gpio_level_e level;

    int ret = cm_gpio_get_level(pin, &level);
    if (ret == 0) {
        lua_pushinteger(L, level);
    } else {
        lua_pushnil(L);
    }
    return 1;
}


static const luaL_Reg gpio_lib[] = {
    {"setup", l_gpio_setup},
    {"write", l_gpio_write},
    {"read", l_gpio_read},
    {NULL, NULL}
};

int luaopen_gpio(lua_State *L) {
    // We can add constants to the library table, e.g. gpio.OUTPUT, gpio.PULL_UP
    luaL_newlib(L, gpio_lib);
    return 1;
}
